1. Introdução (Business Understanding)¶
Este notebook apresenta a Análise Exploratória do Programa de Subvenção ao Prêmio do Seguro Rural (PSR) no Brasil (2006–2025), seguindo a metodologia CRISP-DM. O objetivo é evidenciar:
- Evolução temporal do programa (apólices, prêmio, valor segurado, subvenção);
- Distribuição geográfica por UF/município;
- Padrões por cultura e seguradora;
- Eventos preponderantes causadores de sinistros;
- Retenção de segurados;
- Localidades em crescimento/queda.
Público-alvo: recrutadores e profissionais do agronegócio e seguros rurais.
2. Entendimento dos Dados (Data Understanding)¶
Nesta seção resumimos o dataset consolidado (nível processed) e referências de qualidade provenientes do relatório de colunas gerado na etapa anterior.
In [1]:
# === Setup e carregamento ===
import pandas as pd
import numpy as np
from pathlib import Path
import matplotlib.pyplot as plt
# Caminhos (use relativo ao repositório)
DATA_DIR = Path(r"C:\Users\fred\Documents\Estudo de dados\Projeto\Seguro Rural\data")
PROC = DATA_DIR / 'processed'
INTERIM = DATA_DIR / 'interim'
DOCS = Path('../docs')
# Dataset final esperado (ajuste se necessário)
PARQUET_FINAL = PROC / 'psr_2006_2025.parquet'
# Relatório de colunas (opcional, vindo da etapa anterior)
RELATORIO_COLUNAS = DOCS / 'relatorio_colunas.csv' # mova seu arquivo para docs/
# Carregar dataset final
df = pd.read_parquet(PARQUET_FINAL)
print('Registros:', len(df), '| Colunas:', len(df.columns))
df.head(3)
Registros: 1712384 | Colunas: 68
Out[1]:
| NM_RAZAO_SOCIAL | CD_PROCESSO_SUSEP | NR_PROPOSTA | ID_PROPOSTA | DT_PROPOSTA | DT_INICIO_VIGENCIA | DT_FIM_VIGENCIA | NM_SEGURADO | NR_DOCUMENTO_SEGURADO | NM_MUNICIPIO_PROPRIEDADE | ... | METR_AREA_MEDIA | METR_SUBVENCAO_RELATIVA | MES_APOLICE | NR_DOCUMENTO_SEGURADO_NORM | CHAVE_SEGURADO | PRESENCA_SEGURADO_ANO | FLAG_PREMIO_NULO | FLAG_PREMIO_NEGATIVO | FLAG_GARANTIA_NULA | FLAG_GARANTIA_INVALIDA | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | aliança_do_brasil_seguros_s/a. | 15414901479201927 | 50405357 | 1045544 | 2019-08-29 | 2019-08-29 | 2020-08-28 | jose_procopio_bezerra_neto | ***53043172 | rio_verde | ... | 0.001726 | NaN | 9 | 53043172 | 53043172 | True | True | False | True | False |
| 1 | aliança_do_brasil_seguros_s/a. | 15414901479201927 | 50405359 | 1038777 | 2019-08-29 | 2019-08-29 | 2020-08-28 | joao_augusto_dedemo_prado | ***47332869 | veríssimo | ... | 0.001273 | NaN | 9 | 47332869 | 47332869 | True | True | False | True | False |
| 2 | aliança_do_brasil_seguros_s/a. | 15414901479201927 | 50405361 | 1038713 | 2019-08-29 | 2019-08-29 | 2020-08-28 | joao_augusto_dedemo_prado | ***47332869 | veríssimo | ... | 0.001500 | NaN | 9 | 47332869 | 47332869 | True | True | False | True | False |
3 rows × 68 columns
In [2]:
# === Resumo descritivo e qualidade ===
summary = {
'periodo_min': pd.to_datetime(df['DT_APOLICE'], errors='coerce').min(),
'periodo_max': pd.to_datetime(df['DT_APOLICE'], errors='coerce').max(),
'n_seguradoras': df['NM_RAZAO_SOCIAL'].nunique() if 'NM_RAZAO_SOCIAL' in df.columns else np.nan,
'n_culturas': df['NM_CULTURA_GLOBAL'].nunique() if 'NM_CULTURA_GLOBAL' in df.columns else np.nan,
'n_municipios': df['NM_MUNICIPIO_PROPRIEDADE'].nunique() if 'NM_MUNICIPIO_PROPRIEDADE' in df.columns else np.nan,
'n_ufs': df['SG_UF_PROPRIEDADE'].nunique() if 'SG_UF_PROPRIEDADE' in df.columns else np.nan,
}
pd.Series(summary)
Out[2]:
periodo_min 2006-09-14 00:00:00 periodo_max 2025-08-21 00:00:00 n_seguradoras 20 n_culturas 69 n_municipios 5067 n_ufs 27 dtype: object
In [3]:
# % de nulos em colunas-chave
cols_chave = [
'VL_PREMIO_LIQUIDO','VL_LIMITE_GARANTIA','VALOR_INDENIZAÇÃO',
'VL_SUBVENCAO_FEDERAL','NR_AREA_TOTAL','NM_CULTURA_GLOBAL','SG_UF_PROPRIEDADE'
]
nulos = (
df[cols_chave].isna().mean().sort_values(ascending=False)*100
).round(2).rename('%_nulos')
display(nulos.to_frame())
# Gráfico simples de % nulos (matplotlib sem cores específicas)
plt.figure(figsize=(8,4))
nulos.plot(kind='bar')
plt.title('% de nulos - colunas-chave')
plt.ylabel('%')
plt.xlabel('coluna')
plt.show()
| %_nulos | |
|---|---|
| VL_SUBVENCAO_FEDERAL | 96.02 |
| VALOR_INDENIZAÇÃO | 92.16 |
| VL_PREMIO_LIQUIDO | 91.16 |
| VL_LIMITE_GARANTIA | 65.02 |
| NR_AREA_TOTAL | 37.38 |
| NM_CULTURA_GLOBAL | 0.00 |
| SG_UF_PROPRIEDADE | 0.00 |
Resumo do Entendimento dos Dados (Data Understanding)¶
- Dataset consolidado com 1,7 milhão de registros e 68 variáveis.
- Cobertura temporal: 2006–2025.
- Abrange 20 seguradoras, 69 culturas agrícolas, 5.067 municípios em 27 UFs.
Completude das variáveis-chave:¶
VL_SUBVENCAO_FEDERAL: ~96% nulosVALOR_INDENIZAÇÃO: ~92% nulosVL_PREMIO_LIQUIDO: ~91% nulosVL_LIMITE_GARANTIA: ~65% nulosNR_AREA_TOTAL: ~37% nulos- Variáveis categóricas (
NM_CULTURA_GLOBAL,SG_UF_PROPRIEDADE) → sem nulos
📌 Interpretação: grande parte dos nulos decorre da própria natureza do PSR (nem todas apólices têm subvenção ou indenização).
3. Preparação (Data Preparation) — resumo do pipeline¶
- Camadas:
raw→interim→processed - Tratamentos realizados: padronização de tipos, normalização textual, conversão de datas, remoção de duplicatas por
ID_PROPOSTA - Flags:
FLAG_PREMIO_ZERO,FLAG_RELACAO_PREMIO_SEGURADO,FLAG_SUBVENCAO_EXCESSO,FLAG_PRODUT_*_OUTLIER,FLAG_*DATAS*,FLAG_PREMIO_NULO/GARANTIA_* - Métricas:
METR_TAXA_PREMIO,METR_SINISTRALIDADE,METR_AREA_MEDIA,METR_SUBVENCAO_RELATIVA,ANO_APOLICE,MES_APOLICE - Identificação:
CHAVE_SEGURADO(documento normalizado) para análises de retenção.
4. Análises Exploratórias (Evaluation)¶
4.1 Evolução temporal¶
Perguntas:
- Como evoluíram apólices, valor segurado, prêmio e subvenção ao longo do tempo? Notas de qualidade:
- Calcular séries com e sem registros marcados por flags (ex.:
FLAG_PREMIO_NULO).
In [4]:
# Série histórica: contagem de apólices por ano
serie_apo = df.groupby('ANO_APOLICE', dropna=False)['ID_PROPOSTA'].nunique().sort_index()
display(serie_apo.to_frame('n_apolices'))
plt.figure()
serie_apo.plot()
plt.title('Nº de apólices por ano')
plt.xlabel('Ano')
plt.ylabel('Nº apólices')
plt.show()
| n_apolices | |
|---|---|
| ANO_APOLICE | |
| 2006 | 21743 |
| 2007 | 31168 |
| 2008 | 59802 |
| 2009 | 69039 |
| 2010 | 53145 |
| 2011 | 60556 |
| 2012 | 62158 |
| 2013 | 102583 |
| 2014 | 117597 |
| 2015 | 39892 |
| 2016 | 74331 |
| 2017 | 66352 |
| 2018 | 63062 |
| 2019 | 92683 |
| 2020 | 184253 |
| 2021 | 209199 |
| 2022 | 121255 |
| 2023 | 102811 |
| 2024 | 134618 |
| 2025 | 46137 |
In [13]:
# === Série histórica: valores financeiros (em milhões de R$) ===
by_year = df.groupby('ANO_APOLICE', dropna=False).agg(
valor_segurado=('VL_LIMITE_GARANTIA','sum'),
premio=('VL_PREMIO_LIQUIDO','sum'),
sub_federal=('VL_SUBVENCAO_FEDERAL','sum'),
indenizacao=('VALOR_INDENIZAÇÃO','sum')
).sort_index()
# Converter para milhões
by_year_mi = (by_year / 1e6).round(2)
display(by_year_mi.head())
# Plotar em milhões
plt.figure(figsize=(10,6))
by_year_mi[['valor_segurado','premio','sub_federal','indenizacao']].fillna(0).plot(ax=plt.gca())
plt.title('Séries financeiras por ano (em milhões de R$)', fontsize=12)
plt.xlabel('Ano')
plt.ylabel('R$ milhões')
plt.grid(True, linestyle="--", alpha=0.5)
plt.tight_layout()
plt.show()
| valor_segurado | premio | sub_federal | indenizacao | |
|---|---|---|---|---|
| ANO_APOLICE | ||||
| 2006 | 1879.11 | 3.34 | 1.59 | 1.02 |
| 2007 | 947.55 | 9.31 | 4.34 | 4.89 |
| 2008 | 2326.93 | 13.59 | 7.31 | 11.82 |
| 2009 | 3558.42 | 26.71 | 11.52 | 12.40 |
| 2010 | 2694.04 | 17.78 | 7.78 | 11.26 |
Evolução temporal¶
- Nº de apólices cresceu até 2021, com pico de 209 mil apólices, e queda em anos recentes.
- Valores financeiros em tendência de expansão, com forte aceleração a partir de 2019.
4.2 Distribuição geográfica¶
- Ranking por UF de apólices, prêmio, valor segurado e sinistralidade média.
- (Opcional) Mapa coroplético por UF (requer
geopandase um shapefile/geojson).
In [14]:
# === Rankings por UF (em milhões de R$) ===
uf_agg = df.groupby('SG_UF_PROPRIEDADE', dropna=False).agg(
n_apolices=('ID_PROPOSTA','nunique'),
valor_segurado=('VL_LIMITE_GARANTIA','sum'),
premio=('VL_PREMIO_LIQUIDO','sum'),
sinistralidade=('METR_SINISTRALIDADE','mean')
).sort_values('n_apolices', ascending=False)
# Converter valores para milhões
uf_agg_fmt = uf_agg.copy()
uf_agg_fmt['valor_segurado'] = (uf_agg_fmt['valor_segurado'] / 1e6).round(2)
uf_agg_fmt['premio'] = (uf_agg_fmt['premio'] / 1e6).round(2)
# Renomear colunas para clareza
uf_agg_fmt.rename(columns={
'valor_segurado': 'valor_segurado (R$ mi)',
'premio': 'premio (R$ mi)',
'sinistralidade': 'sinistralidade (média)'
}, inplace=True)
display(uf_agg_fmt.head(15))
| n_apolices | valor_segurado (R$ mi) | premio (R$ mi) | sinistralidade (média) | |
|---|---|---|---|---|
| SG_UF_PROPRIEDADE | ||||
| pr | 640980 | 20636.37 | 340.58 | 1.036168 |
| rs | 358099 | 37056.38 | 515.20 | 2.155295 |
| sp | 236341 | 19371.34 | 523.30 | 2.428079 |
| sc | 126625 | 12770.06 | 259.35 | 1.552355 |
| mg | 107729 | 11295.26 | 141.84 | 3.547424 |
| go | 86398 | 5790.13 | 64.12 | 0.738290 |
| ms | 78779 | 6338.41 | 105.14 | 0.738306 |
| mt | 29581 | 4513.75 | 43.36 | 3.678588 |
| es | 12674 | 437.91 | 1.60 | 0.000000 |
| ba | 11569 | 1443.57 | 15.88 | 0.220777 |
| to | 6184 | 1011.36 | 9.59 | 2.826513 |
| ma | 4579 | 583.60 | 5.43 | 1.384769 |
| pi | 2294 | 371.70 | 4.66 | 8.624914 |
| df | 2268 | 2059.79 | 5.03 | 1.794191 |
| se | 1972 | 118.12 | 0.99 | 0.000000 |
In [21]:
import plotly.express as px
import requests
# === GeoJSON simplificado das UFs ===
url_uf = "https://raw.githubusercontent.com/codeforamerica/click_that_hood/master/public/data/brazil-states.geojson"
geojson_uf = requests.get(url_uf).json()
# Dicionário sigla -> nome (sem acentos, como no GeoJSON)
uf_names = {
'AC':'Acre','AL':'Alagoas','AP':'Amapa','AM':'Amazonas','BA':'Bahia','CE':'Ceara',
'DF':'Distrito Federal','ES':'Espirito Santo','GO':'Goias','MA':'Maranhao','MT':'Mato Grosso',
'MS':'Mato Grosso do Sul','MG':'Minas Gerais','PA':'Para','PB':'Paraiba','PR':'Parana',
'PE':'Pernambuco','PI':'Piaui','RJ':'Rio de Janeiro','RN':'Rio Grande do Norte',
'RS':'Rio Grande do Sul','RO':'Rondonia','RR':'Roraima','SC':'Santa Catarina',
'SP':'Sao Paulo','SE':'Sergipe','TO':'Tocantins'
}
# Preparar DataFrame para o mapa
df_map = uf_agg.reset_index().copy()
df_map["SG_UF_PROPRIEDADE"] = df_map["SG_UF_PROPRIEDADE"].str.upper()
df_map["UF_NAME"] = df_map["SG_UF_PROPRIEDADE"].map(uf_names)
# Criar métricas em milhões/bilhões
df_map["premio_mi"] = (df_map["premio"] / 1e6).round(2)
df_map["valor_segurado_bi"] = (df_map["valor_segurado"] / 1e9).round(2)
df_map["sinistralidade"] = df_map["sinistralidade"].round(2)
# Centralização e projeção para o Brasil
geo_config = dict(
fitbounds="locations",
visible=False,
projection_type="mercator",
center={"lat": -14, "lon": -52}
)
# === 1. Prêmio ===
fig1 = px.choropleth(
df_map,
geojson=geojson_uf,
featureidkey="properties.name",
locations="UF_NAME",
color="premio_mi",
color_continuous_scale="Blues",
title="Prêmio de Seguro Rural por UF (2006–2025, R$ milhões)",
hover_data={"premio_mi": True, "n_apolices": True, "sinistralidade": True}
)
fig1.update_geos(**geo_config)
fig1.show()
# === 2. Valor Segurado ===
fig2 = px.choropleth(
df_map,
geojson=geojson_uf,
featureidkey="properties.name",
locations="UF_NAME",
color="valor_segurado_bi",
color_continuous_scale="Greens",
title="Valor Segurado por UF (2006–2025, R$ bilhões)",
hover_data={"valor_segurado_bi": True, "n_apolices": True, "sinistralidade": True}
)
fig2.update_geos(**geo_config)
fig2.show()
# === 3. Sinistralidade ===
fig3 = px.choropleth(
df_map,
geojson=geojson_uf,
featureidkey="properties.name",
locations="UF_NAME",
color="sinistralidade",
color_continuous_scale="Reds",
title="Sinistralidade Média por UF (2006–2025)",
hover_data={"sinistralidade": True, "n_apolices": True, "premio_mi": True}
)
fig3.update_geos(**geo_config)
fig3.show()
Distribuição geográfica¶
- PR, RS, SP e SC concentram a maior parte das apólices e prêmios.
- Mapas coropléticos mostraram contraste:
- Sul/Sudeste com maior volume,
- Norte/Nordeste com menor penetração do PSR.
- Sinistralidade média mais elevada em MG, MT, PI.
4.3 Análise por cultura¶
- Ranking de culturas por apólices, prêmio e valor segurado.
- Sinistralidade média por cultura.
In [22]:
# === Ranking por cultura (em milhões de R$) ===
cult = df.groupby('NM_CULTURA_GLOBAL', dropna=False).agg(
n_apolices=('ID_PROPOSTA','nunique'),
valor_segurado=('VL_LIMITE_GARANTIA','sum'),
premio=('VL_PREMIO_LIQUIDO','sum'),
sinistralidade=('METR_SINISTRALIDADE','mean')
).sort_values('n_apolices', ascending=False)
# Converter para milhões
cult_fmt = cult.copy()
cult_fmt['valor_segurado'] = (cult_fmt['valor_segurado'] / 1e6).round(2)
cult_fmt['premio'] = (cult_fmt['premio'] / 1e6).round(2)
# Renomear colunas
cult_fmt.rename(columns={
'valor_segurado': 'valor_segurado (R$ mi)',
'premio': 'premio (R$ mi)',
'sinistralidade': 'sinistralidade (média)'
}, inplace=True)
display(cult_fmt.head(20))
# === Gráfico de barras (Top 10 culturas por nº de apólices) ===
top10 = cult_fmt.head(10)['n_apolices']
plt.figure(figsize=(8,5))
top10.plot(kind='barh')
plt.title('Top 10 culturas por nº de apólices')
plt.xlabel('nº apólices')
plt.ylabel('cultura')
plt.gca().invert_yaxis()
plt.grid(axis="x", linestyle="--", alpha=0.5)
plt.show()
| n_apolices | valor_segurado (R$ mi) | premio (R$ mi) | sinistralidade (média) | |
|---|---|---|---|---|
| NM_CULTURA_GLOBAL | ||||
| soja | 728850 | 39182.67 | 488.90 | 1.067488 |
| milho_2ª_safra | 246653 | 8857.74 | 194.18 | 0.521013 |
| uva | 148604 | 9094.96 | 192.69 | 2.860795 |
| trigo | 143830 | 11037.01 | 213.30 | 1.506704 |
| milho_1ª_safra | 91627 | 4600.17 | 40.56 | 0.977428 |
| café | 72083 | 5057.34 | 25.65 | 4.325146 |
| arroz | 59743 | 9292.20 | 57.25 | 1.852670 |
| maçã | 35317 | 8193.51 | 161.13 | 1.467477 |
| cana-de-açúcar | 33265 | 2988.56 | 6.35 | 10.742189 |
| tomate | 26614 | 4526.41 | 290.81 | 3.082442 |
| pecuário | 24826 | 5120.28 | 20.59 | 3.636350 |
| cebola | 21078 | 2000.71 | 99.89 | 1.441182 |
| feijão_1ª_safra | 13382 | 2646.46 | 9.34 | 2.122794 |
| pêssego | 11568 | 705.43 | 31.43 | 2.388052 |
| ameixa | 8050 | 427.37 | 41.53 | 2.424768 |
| caqui | 6409 | 496.77 | 41.13 | 2.253781 |
| sorgo | 6127 | 293.02 | 5.34 | 0.385538 |
| floresta | 4759 | 4840.01 | 6.94 | 18.516117 |
| cevada | 4640 | 725.25 | 6.73 | 2.034733 |
| alho | 2765 | 635.53 | 27.21 | 1.594235 |
Análise por cultura¶
- Soja domina o PSR em nº de apólices e valor segurado.
- Outras culturas relevantes: milho (1ª e 2ª safra), trigo, uva, café, arroz.
- Culturas com sinistralidade elevada: floresta, cana-de-açúcar, tomate.
4.4 Análise por seguradora¶
- Ranking de seguradoras por nº de apólices e prêmio.
- Evolução de participação ao longo do tempo (se houver interesse).
In [9]:
seg = df.groupby('NM_RAZAO_SOCIAL', dropna=False).agg(
n_apolices=('ID_PROPOSTA','nunique'),
premio=('VL_PREMIO_LIQUIDO','sum'),
sinistralidade=('METR_SINISTRALIDADE','mean')
).sort_values('n_apolices', ascending=False)
display(seg.head(15))
# Barras das top 10 por nº apólices
plt.figure()
seg.head(10)['n_apolices'].plot(kind='barh')
plt.title('Top 10 seguradoras por nº de apólices')
plt.xlabel('nº apólices')
plt.ylabel('seguradora')
plt.gca().invert_yaxis()
plt.show()
| n_apolices | premio | sinistralidade | |
|---|---|---|---|
| NM_RAZAO_SOCIAL | |||
| brasilseg_companhia_de_seguros | 595443 | 235306692.0 | 0.940515 |
| essor_seguros_s.a. | 232637 | 465665151.0 | 1.626880 |
| mapfre_seguros_gerais_s.a. | 230985 | 36344628.0 | 1.368887 |
| swiss_re_corporate_solutions_brasil_s.a. | 131220 | 70026310.0 | 4.361593 |
| allianz_seguros_s.a | 102612 | 31420958.0 | 1.916051 |
| nobre_seguradora_do_brasil_s.a | 82500 | 90679014.0 | 3.397220 |
| sancor_seguros_do_brasil_s.a. | 79168 | 74702697.0 | 1.536240 |
| fairfax_brasil_seguros_corporativos_s/a | 54999 | 45250088.0 | 3.198631 |
| newe_seguros_s.a | 50265 | 52769113.0 | 0.537558 |
| tokio_marine_seguradora_s.a. | 38657 | 353875952.0 | 1.416964 |
| porto_seguro_companhia_de_seguros_gerais | 35968 | 494307909.0 | 3.073472 |
| sompo_seguros_s/a | 20286 | 13953045.0 | 0.449780 |
| aliança_do_brasil_seguros_s/a. | 18474 | 46870262.0 | 1.175323 |
| sombrero_seguros_s/a | 18345 | 14748120.0 | 0.235262 |
| too_seguros_s.a. | 13709 | 7706937.0 | 1.711258 |
Análise por seguradora¶
- Maior nº de apólices: Brasilseg.
- Maior prêmio concentrado em seguradoras como Essor e Porto Seguro.
- Há diferenças marcantes na sinistralidade média entre seguradoras.
4.5 Eventos de sinistro¶
- Frequência e impacto financeiro dos EVENTO_PREPONDERANTE.
- Ranking por UF/cultura.
In [23]:
# === Eventos preponderantes ===
evt = df.assign(evento=df['EVENTO_PREPONDERANTE'].fillna('não informado'))
evt_agg = evt.groupby('evento', dropna=False).agg(
n_apolices=('ID_PROPOSTA','size'),
indenizacao=('VALOR_INDENIZAÇÃO','sum')
).sort_values('indenizacao', ascending=False)
# Converter indenização para milhões
evt_agg['indenizacao (R$ mi)'] = (evt_agg['indenizacao'] / 1e6).round(2)
# Selecionar colunas finais com nomes claros
evt_agg_fmt = evt_agg[['n_apolices', 'indenizacao (R$ mi)']]
# Mostrar tabela (Top 15)
display(evt_agg_fmt.head(15).style.set_properties(**{'text-align': 'center'})
.set_table_styles([dict(selector='th', props=[('text-align', 'center')])]))
| n_apolices | indenizacao (R$ mi) | |
|---|---|---|
| evento | ||
| seca | 180687 | 593.130000 |
| granizo | 75823 | 336.950000 |
| geada | 42746 | 182.940000 |
| chuva_excessiva | 19773 | 57.450000 |
| incêndio | 610 | 30.680000 |
| morte | 1554 | 27.530000 |
| inundação/tromba_d´água | 4069 | 18.110000 |
| ventos_fortes/frios | 5518 | 11.130000 |
| demais_causas | 44089 | 6.010000 |
| variação_excessiva_de_temperatura | 1273 | 2.860000 |
| queda_de_parreiral | 297 | 0.970000 |
| doenças_e_pragas | 34 | 0.190000 |
| raio | 61 | 0.140000 |
| perda_de_qualidade | 31 | 0.140000 |
| - | 1335760 | 0.010000 |
Eventos de sinistro¶
- Seca, granizo e geada respondem pela maior parte das indenizações.
- Eventos de baixa frequência, mas alto impacto local, incluem chuva excessiva e incêndio.
4.6 Retenção de segurados¶
- % de segurados que permanecem de um ano para o outro.
- Quebrar por UF/cultura (opcional).
In [24]:
presenca = (
df.dropna(subset=['CHAVE_SEGURADO','ANO_APOLICE'])
.groupby(['ANO_APOLICE','CHAVE_SEGURADO']).size().reset_index(name='n')
)
anos = sorted(presenca['ANO_APOLICE'].unique())
rows=[]
for a in anos:
base_a = set(presenca.loc[presenca['ANO_APOLICE']==a, 'CHAVE_SEGURADO'])
base_b = set(presenca.loc[presenca['ANO_APOLICE']==a+1, 'CHAVE_SEGURADO'])
if len(base_a)==0:
continue
ret = len(base_a & base_b)/len(base_a)
rows.append({'ano': int(a), 'retencao_t_to_t1': ret})
ret_df = pd.DataFrame(rows).sort_values('ano')
display(ret_df)
# Plot corrigido
plt.figure(figsize=(10,5))
plt.plot(ret_df['ano'].to_numpy(), ret_df['retencao_t_to_t1'].to_numpy(), marker='o')
plt.title('Retenção de segurados (t → t+1)')
plt.xlabel('Ano')
plt.ylabel('Retenção (%)')
plt.ylim(0,1) # eixo fixo de 0 a 1
plt.grid(True, linestyle="--", alpha=0.6)
plt.show()
| ano | retencao_t_to_t1 | |
|---|---|---|
| 0 | 2006 | 0.584691 |
| 1 | 2007 | 0.712186 |
| 2 | 2008 | 0.678336 |
| 3 | 2009 | 0.567272 |
| 4 | 2010 | 0.664593 |
| 5 | 2011 | 0.672739 |
| 6 | 2012 | 0.790807 |
| 7 | 2013 | 0.729815 |
| 8 | 2014 | 0.294511 |
| 9 | 2015 | 0.645214 |
| 10 | 2016 | 0.599294 |
| 11 | 2017 | 0.586453 |
| 12 | 2018 | 0.686626 |
| 13 | 2019 | 0.784253 |
| 14 | 2020 | 0.733183 |
| 15 | 2021 | 0.495902 |
| 16 | 2022 | 0.556983 |
| 17 | 2023 | 0.636441 |
| 18 | 2024 | 0.295393 |
| 19 | 2025 | 0.000000 |
Retenção de segurados¶
- Retenção média variou entre 50–80%, com quedas bruscas em 2014, 2021 e 2024.
- Picos de fidelização ocorreram em 2012 e 2019 (>75%).
4.7 Crescimento e queda (YoY)¶
- Identificar localidades (UF/município) que mais cresceram/caíram em nº de apólices e prêmio.
In [25]:
# === Cálculo de YoY com limpeza ===
loc_year = (
df.groupby(['ANO_APOLICE','SG_UF_PROPRIEDADE','NM_MUNICIPIO_PROPRIEDADE'], dropna=False)
.agg(n_apolices=('ID_PROPOSTA','nunique'),
premio=('VL_PREMIO_LIQUIDO','sum'))
.reset_index()
.sort_values(['SG_UF_PROPRIEDADE','NM_MUNICIPIO_PROPRIEDADE','ANO_APOLICE'])
)
# Variações ano a ano
loc_year['variação_apolices_yoy (%)'] = loc_year.groupby(
['SG_UF_PROPRIEDADE','NM_MUNICIPIO_PROPRIEDADE']
)['n_apolices'].pct_change() * 100
loc_year['variação_premio_yoy (%)'] = loc_year.groupby(
['SG_UF_PROPRIEDADE','NM_MUNICIPIO_PROPRIEDADE']
)['premio'].pct_change() * 100
# Filtrar municípios com pelo menos 20 apólices no ano anterior
loc_year['n_apolices_ano_anterior'] = loc_year.groupby(
['SG_UF_PROPRIEDADE','NM_MUNICIPIO_PROPRIEDADE']
)['n_apolices'].shift(1)
loc_year_filtrado = loc_year[loc_year['n_apolices_ano_anterior'] >= 20].copy()
# Remover infinitos e valores extremos
loc_year_filtrado.replace([np.inf, -np.inf], np.nan, inplace=True)
# Último ano disponível
ultimo = loc_year_filtrado['ANO_APOLICE'].max()
crescimentos = (
loc_year_filtrado[loc_year_filtrado['ANO_APOLICE']==ultimo]
.sort_values('variação_apolices_yoy (%)', ascending=False)
.head(15)
)
quedas = (
loc_year_filtrado[loc_year_filtrado['ANO_APOLICE']==ultimo]
.sort_values('variação_apolices_yoy (%)', ascending=True)
.head(15)
)
# Mostrar resultados
display(crescimentos[['SG_UF_PROPRIEDADE','NM_MUNICIPIO_PROPRIEDADE','n_apolices',
'variação_apolices_yoy (%)','variação_premio_yoy (%)']])
display(quedas[['SG_UF_PROPRIEDADE','NM_MUNICIPIO_PROPRIEDADE','n_apolices',
'variação_apolices_yoy (%)','variação_premio_yoy (%)']])
| SG_UF_PROPRIEDADE | NM_MUNICIPIO_PROPRIEDADE | n_apolices | variação_apolices_yoy (%) | variação_premio_yoy (%) | |
|---|---|---|---|---|---|
| 47540 | rs | coronel_barros | 44 | 41.935484 | 88.536396 |
| 46163 | es | vila_pavão | 44 | 18.918919 | NaN |
| 47053 | pr | califórnia | 40 | 11.111111 | NaN |
| 48217 | sp | ribeirão_grande | 26 | 4.000000 | 36.647042 |
| 47067 | pr | carambeí | 86 | 3.614458 | -11.445013 |
| 47319 | pr | rio_branco_do_ivaí | 40 | 0.000000 | NaN |
| 47401 | pr | uniflor | 36 | -2.702703 | 210.292958 |
| 47112 | pr | espigão_alto_do_iguaçu | 40 | -4.761905 | -100.000000 |
| 47710 | rs | saldanha_marinho | 37 | -5.128205 | -65.115011 |
| 46783 | ms | douradina | 72 | -8.860759 | -66.666667 |
| 46739 | mg | unaí | 64 | -11.111111 | NaN |
| 47404 | pr | ventania | 20 | -13.043478 | -100.000000 |
| 46632 | mg | passa_tempo | 75 | -13.793103 | 61.804710 |
| 47392 | pr | tibagi | 147 | -15.517241 | -89.240710 |
| 48249 | sp | sumaré | 39 | -17.021277 | -17.882348 |
| SG_UF_PROPRIEDADE | NM_MUNICIPIO_PROPRIEDADE | n_apolices | variação_apolices_yoy (%) | variação_premio_yoy (%) | |
|---|---|---|---|---|---|
| 47922 | sc | turvo | 1 | -99.702381 | -100.000000 |
| 47892 | sc | praia_grande | 1 | -99.099099 | -100.000000 |
| 47275 | pr | paulo_frontin | 1 | -99.090909 | -100.000000 |
| 47504 | rs | cacequi | 1 | -99.090909 | -83.414967 |
| 47508 | rs | camaquã | 1 | -98.989899 | -100.000000 |
| 47913 | sc | são_joão_do_sul | 1 | -98.969072 | -98.111143 |
| 47761 | rs | são_pedro_do_sul | 1 | -98.823529 | NaN |
| 47908 | sc | são_domingos | 1 | -98.529412 | -100.000000 |
| 46819 | ms | paraíso_das_águas | 1 | -98.387097 | NaN |
| 47478 | rs | arroio_grande | 3 | -98.203593 | -100.000000 |
| 47089 | pr | coronel_domingos_soares | 1 | -98.181818 | NaN |
| 46328 | go | uruaçu | 1 | -98.076923 | NaN |
| 46052 | ba | formosa_do_rio_preto | 1 | -98.000000 | -98.888177 |
| 47488 | rs | barros_cassal | 1 | -97.916667 | NaN |
| 46715 | mg | são_joão_del_rei | 1 | -97.916667 | -100.000000 |
Crescimento e queda (YoY)¶
- Municípios como Coronel Barros (RS) mostraram forte crescimento em 2025 (+42%).
- Outros, como Turvo (SC), praticamente saíram do programa (queda de -99%).
- Importante filtrar municípios com pelo menos 20 apólices no ano anterior para evitar distorções estatísticas.
5. Discussão e Limitações¶
Principais achados:¶
- Forte concentração regional (Sul/Sudeste).
- Cultura da soja é dominante, mas milho e trigo também são relevantes.
- Seca é o principal evento de sinistro, refletindo vulnerabilidade climática.
- Retenção irregular: há anos com forte fidelização e anos de queda abrupta.
- Alguns municípios estão em clara expansão, enquanto outros praticamente abandonaram o PSR.
Limitações:¶
- Elevada taxa de nulos em variáveis financeiras (prêmio, limite, subvenção, indenização).
- Inconsistências em datas de vigência, mantidas como flags.
- Dependência de dados administrativos, sujeitos a falhas de preenchimento por seguradora/ano.
Oportunidades:¶
- Enriquecimento com dados meteorológicos/satelitais para explicar sinistros.
- Criação de dashboards interativos (Plotly, Streamlit, PowerBI).
- Modelagem preditiva para risco climático e retenção de segurados.
6. Conclusão¶
- Foi construído um pipeline reprodutível (raw → interim → processed), documentado com dicionário de variáveis e testes de qualidade.
- As análises exploratórias cobriram:
- Negócio: dinâmica do PSR ao longo de 20 anos;
- Geografia: distribuição por UF/município;
- Produção: padrões por cultura;
- Mercado: seguradoras;
- Risco: eventos de sinistro;
- Clientes: retenção e churn.
In [ ]: